/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package imperio.simulador;

import imperio.Imperio;
import imperio.Sistema;
import imperio.controlador.Cap;
import imperio.eventos.*;
import imperio.population.Individuo;
import imperio.population.Populacao;
import imperio.xmlReader.ReaderXmlFile;
import java.util.Iterator;

/**
 *
 * @author Bernardo
 */
public class Simulador {

    private static Simulador simulador;   
    public static float mi,rho,delta;
    private static int numObservacao;
    public static int numPatrulhas, numSistemas, popInicial, maxPop;
    public static double tempoSimulacao, tempoCorrente, tempoObservacao, consObservacao;
    public static Evento eventoCorrente;  
    public static int Matriz[][];
    private static Individuo melhorIndividuo;
    
    public static Simulador getInstance(){
        if(simulador == null)
            simulador = new Simulador();
         return simulador;
    }
    private Simulador(){
       
    }
    
    /**Método principal, controla o processo de execução dos eventos e o momento de parada do programa.      
     */

    public static void main(String[] args) {
        ReaderXmlFile.getInstance().readXml();  
        Imperio.getInstance();           
        Populacao.getInstance();        
        Cap.getInstance();
        aplcarEvIniciais(); 
        melhorIndividuo = new Individuo();
        numObservacao = 1;
        tempoObservacao = consObservacao;
        tempoCorrente = 0;
        
        melhorIndividuo = Populacao.individuos.first();
        
        while(tempoCorrente < tempoSimulacao){              
            if(melhorIndividuo.getConforto() < Populacao.individuos.first().getConforto())
                copyIndividuo();
            if(Cap.listaEventos.isEmpty() || Populacao.individuos.isEmpty() || Populacao.individuos.first().getConforto() == 1){
                showTerminal();                
                break;
            }
            Cap.removerEvCap();
            if(tempoObservacao > tempoCorrente && tempoObservacao < eventoCorrente.getTempo()){                   
                showTerminal();
                tempoObservacao = tempoObservacao + consObservacao;
                numObservacao++;
            }               
            tempoCorrente = eventoCorrente.getTempo();            
            eventoCorrente.simularEvento();   
        }
        
    }  
    
    /**Método para clonar o individuo de melhor conforto da população.
      
     */
    
    private static void copyIndividuo(){
        Individuo temp = Populacao.individuos.first();
        melhorIndividuo.setConforto(temp.getConforto());
        melhorIndividuo.settPoliciamento(temp.gettPoliciamento());
        melhorIndividuo.settOtiPoliciamento(temp.gettMinorante());
        melhorIndividuo.setSistemas(Imperio.getInstance().getSistemas());
        for (int i = 0; i < temp.getPatrulhas().size(); i++) {                       
            for (int j = 0; j < temp.getPatrulhas().get(i).getSistemasPatrulhados().size(); j++) {                
                melhorIndividuo.getPatrulhas().get(i).getSistemasPatrulhados().add(temp.getPatrulhas().get(i).getSistemasPatrulhados().get(j));                    
            }           
        }
    }
    
    /**Método para aplicar os eventos iniciais na população. Para cada individuo são adicionados os eventos de: reproduçao, morte e mutação.      
     */

    private static void aplcarEvIniciais() {  

        Iterator<Individuo> iterator = Populacao.individuos.iterator();
        while(iterator.hasNext()){
            Individuo individuo = iterator.next();
            Cap.adcionarEvCap(new Reproducao(individuo)) ;
            Cap.adcionarEvCap(new Morte(individuo));
            Cap.adcionarEvCap(new Mutacao(individuo));            
        }   
    }
    
    /**Método para apresentação dos resultados parciais ou final no terminal. São mostrados os seguintes dados: Número da observaçao,
     * instante atual, número de eventos realizados, dimensão da população, número de epidemiais que ocorreram, a forma como os sistemas
     * estão distribuidos entre as patrulhas, o tempo de policiamento do individuo com melhor conforto e o valor do conforto.      
     */
    
    private static void showTerminal(){               
        System.out.println("Observação "+ numObservacao);
        System.out.println("Instante actual: "+ tempoObservacao);
        System.out.println("Número de eventos realizados: "+ Cap.countEv);
        System.out.println("Dimensão da população: "+ Populacao.individuos.size());
        System.out.println("Número de epidemias: "+ Epidemia.countEpidemias);
        System.out.print("Distribuição pelas patrulhas: ");
        System.out.print("{");        
        for (int i = 0; i < melhorIndividuo.getPatrulhas().size(); i++) {
            System.out.print("{");
            if(!melhorIndividuo.getPatrulhas().get(i).getSistemasPatrulhados().isEmpty()){
            for (int j = 0; j < Populacao.individuos.first().getPatrulhas().get(i).getSistemasPatrulhados().size(); j++) {
                 Sistema sistema = Populacao.individuos.first().getPatrulhas().get(i).getSistemasPatrulhados().get(j);
                 int id = sistema.getId() + 1;
                 if(j == 0)
                 System.out.print(""+ id);
                 else
                 System.out.print(","+ id);                
            }
            }
            System.out.print("}");                     
        }
        System.out.println("}");
        System.out.println("Tempo de policiamento do império: "+ melhorIndividuo.gettPoliciamento());
        System.out.println("Conforto: " +melhorIndividuo.getConforto() + "\n\n");       
    }
}
